#ifndef RENDERER
#define RENDERER

#include <vector>
#include "Shader.hpp"
#include "Text.hpp"
#include "VAO.hpp"
#include "Utils/Math/Matrix4.hpp"

namespace red{
	class Device;

	class REDAPI Renderer{
    public:
		Renderer();
		~Renderer();

        /// \brief Initialize the Renderer from Window
		/// \param pDevice : main engine Device used
        void Init(Device* pDevice);

        /// \brief Function called before rendering every frame
        void BeginScene() const;

		/// \brief Render the drawable objects of the current frame
		void Render();

		/// \brief Add a VAO to be drawn next frame
		void Draw(VAO &pVao);

		void DrawVAO(VAO* pVao);
		

		// Matrix
			/// \brief Change the current 2D Projection Matrix
			void Set2DProjectionMatrix(const Matrix4 &pProj) { m2DProjectionMatrix = pProj; }
			
			/// \brief Change the current 3D Projection Matrix
			void Set3DProjectionMatrix(const Matrix4 &pProj) { m3DProjectionMatrix = pProj; }
			
			/// \brief Change the current 3D View Matrix. Changes also the ViewProj and Normal Matrices accordingly
			void Set3DViewMatrix(const Matrix4 &pView){ 
				m3DViewMatrix = pView; 
				m3DViewProjMatrix = m3DViewMatrix * m3DProjectionMatrix;
				m3DNormalMatrix = m3DViewMatrix.Inverse();
				m3DNormalMatrix = m3DNormalMatrix.Transpose();
			}

			/// Getters
			const Matrix4& Get2DProjectionMatrix() const { return m2DProjectionMatrix; }
			const Matrix4& Get3DProjectionMatrix() const { return m3DProjectionMatrix; }
			const Matrix4& Get3DViewProjMatrix() const { return m3DViewProjMatrix; }
			const Matrix4& Get3DNormalMatrix() const { return m3DNormalMatrix; }
			const Matrix4& Get3DViewMatrix() const { return m3DViewMatrix; }
		
			Shader* s1;
	private:
		/// Pointer on primary Device
		Device* mDevice;

		/// Matrices used by the renderer
		Matrix4 m3DViewMatrix, m3DProjectionMatrix, m3DViewProjMatrix, m3DNormalMatrix;
		Matrix4 m2DProjectionMatrix;

		/// Total entities rendered this frame
		Text mEntityNumberText;
		u16 mEntityNumber, mLastFrameEntityNumber;

		/// Next frame rendering list
		typedef std::vector<VAO*> VAOList;
		VAOList::iterator mVAOListIt;
		VAOList mVAOList;

		/// Next frame rendering list
		typedef std::vector<Text*> TextList;
		TextList::iterator mTextListIt;
		TextList mTextList;

		// Internal functions
			/// \brief VAO Rendering
			void RenderVAOs();
	};
}
#endif